% Function: read tdms file for theraml error
function r = TDMSRead(filepath)
    % the absolute path for NI Lib
    libfolder = 'D:\Workspace\Matlab\NI Lib';

    % dll and header file path
    dllpath = fullfile(libfolder, 'dev\bin\64-bit\nilibddc.dll');
    hpath   = fullfile(libfolder, 'dev\include\64-bit\nilibddc_m.h');

    libname = 'nilibddc';

    % initialize
    r = struct;

    % Step 1:
    % load dll(remember to call unloadlibrary)
    if ~libisloaded(libname)
        loadlibrary(dllpath, hpath);
    end

    % display shared library function signatures
    % libfunctionsview(libname);

    % check whether file exist
    if ~exist(filepath, 'file')
        error([filepath, ' not exist']);
    end

    % Step 2:
    % open TMDS file(remember to call DDC_CloseFile)
    fileIn = 0;
    [err, ~, ~, file] = calllib(libname, 'DDC_OpenFileEx', filepath, 'TDMS', 1, fileIn);
    if err
        error(['open TDMS file failed: ', num2str(err)]);
    end

    % Step 3:
    % get number of channel groups
    ngrpsIn = 0;
    [err, ngrps] = calllib(libname, 'DDC_GetNumChannelGroups', file, ngrpsIn);
    if err
        error(['get number of channels failed: ', num2str(err)]);
    end

    % get channel groups
    if ngrps < 2
        error(['number of channel groups is ', num2str(ngrps)]);
    else
        pgrps = libpointer('int64Ptr', zeros(1, ngrps));
        [err, grps] = calllib(libname, 'DDC_GetChannelGroups', file, pgrps, ngrps);
    end

    % Step 4:
    %% Eddy group %%
    % get number of channels
    nchansIn = 0;
    [err, nchans] = calllib(libname, 'DDC_GetNumChannels', grps(1), nchansIn);

    % get channels
    if nchans > 0
        pchans = libpointer('int64Ptr', zeros(1, nchans));
        [err, chans] = calllib(libname, 'DDC_GetChannels', grps(1), pchans, nchans);
    else
        error('number of channels in eddy group error');
    end

    % get number of values
    nvalsIn = 0;
    [err, nvals] = calllib(libname, 'DDC_GetNumDataValues', chans(1), nvalsIn);

    % preallocate
    r.Eddy = zeros(nvals, nchans - 1);

    % get values of channels
    for i = 2 : nchans
        % get channel data type
        typeIn = 0;
        [err, dtype] = calllib(libname, 'DDC_GetDataType', chans(i), typeIn);

        % get channel values
        if strcmp(dtype, 'DDC_Double')
            pvals = libpointer('doublePtr', zeros(1, nvals));
            [err, vals] = calllib(libname, 'DDC_GetDataValues', chans(i), 0, nvals, pvals);
            setdatatype(vals, 'doublePtr', 1, nvals);

            % save values
            r.Eddy(:, i - 1) = (vals.Value);
        end
    end

    %% Temp group %%
    % get number of channels
    nchansIn = 0;
    [err, nchans] = calllib(libname, 'DDC_GetNumChannels', grps(2), nchansIn);

    % get channels
    if nchans > 0
        pchans = libpointer('int64Ptr', zeros(1, nchans));
        [err, chans] = calllib(libname, 'DDC_GetChannels', grps(2), pchans, nchans);
    else
        error('number of channels in eddy group error');
    end

    % get number of values
    nvalsIn = 0;
    [err, nvals] = calllib(libname, 'DDC_GetNumDataValues', chans(1), nvalsIn);

    % preallocate
    r.Temp = zeros(nvals, nchans - 1);

    % get values of channels
    for i = 2 : nchans
        % get channel data type
        typeIn = 0;
        [err, dtype] = calllib(libname, 'DDC_GetDataType', chans(i), typeIn);

        % get channel values
        if strcmp(dtype, 'DDC_Double')
            pvals = libpointer('doublePtr', zeros(1, nvals));
            [err, vals] = calllib(libname, 'DDC_GetDataValues', chans(i), 0, nvals, pvals);
            setdatatype(vals, 'doublePtr', 1, nvals);

            % save values
            r.Temp(:, i - 1) = (vals.Value);
        end
    end

    % close file
    err = calllib(libname, 'DDC_CloseFile', file);

    % unload dll
    unloadlibrary(libname);
end
